package tirateima.controlador;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.List;
import java.util.ListIterator;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import sun.print.resources.serviceui;
import tirateima.gui.arquivos.AbstractArquivo;
import tirateima.gui.arquivos.VarBinFile;
import tirateima.gui.arquivos.VarFile;
import tirateima.gui.arquivos.VarText;
import tirateima.gui.variaveis.VarArray;
import tirateima.gui.variaveis.VarChar;
import tirateima.gui.variaveis.VarGrade;
import tirateima.gui.variaveis.VarInteger;
import tirateima.gui.variaveis.VarReal;
import tirateima.gui.variaveis.VarRecord;
import tirateima.gui.variaveis.VarString;
import tirateima.gui.variaveis.Variavel;
import tirateima.parser.TiraTeimaParserConstants;
import tirateima.parser.Token;

import com.sun.corba.se.impl.orbutil.closure.Constant;

/**
 * Comando de chamada de operação, que pode ser funções do sistema
 * (manipulação de arquivos, write) ou de função definida pelo
 * usuário.
 * 
 * @author Luciano Santos
 */
@SuppressWarnings("unchecked")
public class CommandOperationCall extends Command
		implements TiraTeimaParserConstants {
	
	private Token cmd;
	List<Object> args;
	
	private Stack<Object> previous_values_stack_Fread = new Stack<Object>();
	
	public CommandOperationCall(Token operation, List<Object> args) {
		this.cmd = operation;
		this.args = args;
	}
	
	/**
	 * Implementa o execute herdado do comando.
	 * 
	 * Recebe os tipos de operações e as executa.
	 */
	public void execute(Controlador c)
			throws TiraTeimaLanguageException {
		
		AbstractArquivo arq;
		
		switch (cmd.kind) {
			//case KW_READ:
			case KW_READLN:
			case KW_CLOSE:
			case KW_OPEN:
			case KW_BINOPEN:
			case KW_FSCANF:
			case KW_FREAD:
			case KW_FWRITE:
			case KW_FPRINTF:
			case KW_FSEEK:
			case KW_FGETC:
				if ((arq = getFile(c, args)) == null)
					gerarErro("Arquivo não encontrado!");
				
				//remove o primeiro argumento para usar o método executeFileOperation
				Object argumento = args.remove(0);
				
				executeFileOperation(c, cmd, arq, args);
				
				//restaura o primeiro argumento para caso o comando seja re-executado
				args.add(0, argumento);
				
				break;
			case KW_WRITE:
			//case KW_WRITELN:
				try {
					if ((arq = getFile(c, args)) == null)
						gerarErro("Arquivo não encontrado!");
					args.remove(0);
					executeWriteOperation(c, cmd, arq, args);
					break;
				} catch (TiraTeimaLanguageException e) {
					executeWriteOperation(c, cmd, null, args);
				}
				break;
			case KW_COMMENT:
				executeAlertOperation(c, cmd, args);
				break;
			case KW_STRLEN:
				try {
					executeStrlenOperation(c, cmd, args);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			case KW_STRCMP:
				try {
					executeStrcmpOperation(c, cmd, args);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			case KW_MOD:
				try {
					//executeModOperation(c, cmd, args);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			case KW_COS:
				try {
					executeCosOperation(c, cmd, args);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			case KW_SQRT:
				try {
					executeSqrtOperation(c, cmd, args);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			case KW_SIN:
				try {
					executeSinOperation(c, cmd, args);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			case KW_SOUND:
				executeSoundOperation(c, cmd);
				break;
		}
	}
	
	@Override
	public void revert(final Controlador c) throws TiraTeimaLanguageException,
			ExecutionException {
		
		switch (cmd.kind) {
			case KW_BINOPEN:
			case KW_OPEN: 
				AbstractArquivo arq = null;
				if ((arq = getFile(c, args)) == null)
						gerarErro("Arquivo não encontrado!");
				try {
					arq.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				break;
				
			case KW_CLOSE:
				arq = null;
				if ((arq = getFile(c, args)) == null)
						gerarErro("Arquivo não encontrado!");
				try {
					arq.open(arq.getFileNameAux());
				} catch (IOException e) {
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			
			case KW_FREAD:
				recuperaValoresAntigos(c, previous_values_stack_Fread, (Stack<Object>)args.get(1));
				break;
						
		}
		
	}

	/**
	 * Recebe um gerador e argumentos e retorna um arquivo.
	 * 
	 * Usada para pegar o arquivo do gerenciador de arquivos.
	 * @param g
	 * @param args
	 * @return
	 * @throws TiraTeimaLanguageException
	 */
	private AbstractArquivo getFile(Controlador c, List<Object> args)
			throws TiraTeimaLanguageException {
		//Pilha auxiliar para armazenar temporariamente os valores da pilha.
		Stack<Object> pilhaAux = new Stack<Object>();
		
		ListIterator<Object> i = args.listIterator();
		if (!i.hasNext())
			gerarErro("Nome de arquivo era esperado");
		
		/** checa se o primeiro é um arquivo*/
		Object obj = i.next();
		if (obj instanceof Stack<?>){
			Stack<Object> stack = (Stack<Object>) obj;
			if (stack.size() == 1) {
				String name = (String) stack.pop();
				pilhaAux.push(name);
				restaurarPilha(stack, pilhaAux);
				obj = stack;
				return c.ga.getArquivo(name);
			}
			else
				gerarErro("Nome de arquivo era esperado.");
		}
		else
			gerarErro("Nome de arquivo era esperado.");
		
		return null;
	}

	/**
	 * Executa uma operação de arquivo.
	 * 
	 * Recebe um tipo de operação sobre o arquivo e gera erro se houver problema. 
	 * Caso não haja erro, executa a operação solicitada sobre o arquivo.
	 * 
	 * @param g
	 * @param cmd
	 * @param arq
	 * @param args
	 * @throws TiraTeimaLanguageException
	 */
	private void executeFileOperation(
			Controlador c,
			Token cmd,
			AbstractArquivo arq,
			List<Object> args) throws TiraTeimaLanguageException {
		Object aux;
		
		try {
			switch (cmd.kind) {
				case KW_FGETC:
					executeGetcOperation(c, cmd, arq, args);
				break;
				case KW_FSCANF:
					executeScanfOperation(c, cmd, arq, args);
					break;
				case KW_FPRINTF:
					executePrintfOperation(c, cmd, arq, args);
					break;
				case KW_FREAD:
					executeFReadOperation(c, cmd, arq, args);
					break;
				case KW_FWRITE:
					executeFWriteOperation(c, cmd, arq, args);
					break;
					
				case KW_BINOPEN:
				case KW_OPEN:
					
					if (args.size() != 1)
						gerarErro("Número de parâmetros incorreto para comando 'open'.");
					aux = args.get(0);
					if (!(aux instanceof String)) {
						gerarErro("Uma string era esperada.");
					}
					arq.open((String) aux);
					break;
			
				case KW_FSEEK:
					int posicao = 0;
					String seekset;
					Object obj;
					
					if (args.size() != 2)
						gerarErro("Número de parâmetros incorreto para comando 'fseek'.");
					obj = args.get(0);

					if (obj instanceof Stack)
					{
						System.out.println("stack");
						posicao = (Integer)getValue(c, (List<Object>) obj);
					}
					else if ((obj instanceof Constant) || ( obj instanceof Integer))
						posicao = new Integer(obj.toString());
		
				
					seekset = args.get(1).toString();
					if (arq instanceof VarFile)
						((VarFile)arq).atualizaPosicaoPonteiro(posicao, seekset);
					else if (arq instanceof VarBinFile)
						((VarBinFile)arq).atualizaPosicaoPonteiro(posicao, seekset);
						
					break;
				case KW_CLOSE:
					if (args.size() != 0)
						gerarErro("Número de parâmetros incorreto para comando 'close'.");
					arq.close();
					break;
				//case KW_READ:
				case KW_READLN:
					executeReadOperation(c, cmd, arq, args);
					break;
			}
		} catch (Exception e) {
			gerarErro("Falha ao executar operação no arquivo.");
			e.printStackTrace();
		}
	}

	private void executeGetcOperation(Controlador c, Token cmd2,
			AbstractArquivo arq, List<Object> args2) throws TiraTeimaLanguageException {
		int size = args.size();
		Variavel var;
		
		Object arg = null;
		Object value = null;
		
		System.out.println("Operacao getc:");
		
		for (int i=0;i<size;i++)
		{
		   arg = args.get(i);
		   if (!(arg instanceof Stack))
		   {
			   gerarErro("Era esperado uma variavel.");
		   }  
		   var = getVariavel((Stack<Object>)arg, c);
		   
		   if (!(var instanceof VarChar))
		   {
			   gerarErro("Era esperado um caractere.");
		   } 
		   
		   value = ((VarFile)arq).getNextChar();
		   System.out.println("  char:" + value);
		   setValue(c, (Stack<Object>) arg, value);
		}
		
		((VarFile)arq).atualizaConteudo();
		
	}

	private Variavel getVariavel(Stack<Object>  first, Controlador c)
	{
		ListIterator<Object> i = ((Stack<Object>) first).listIterator();
		Variavel v = c.mostrador.getCopiaVariavel((String) i.next());
		while (i.hasNext()) {
			Object aux = i.next();
			if (aux instanceof String) {
				v = ((VarRecord) v).getCopiaCampo((String) aux);
			}/* else if (aux instanceof Index){
				Object value = getValue(c, first);
				if (value instanceof Integer) {
					v = new VarInteger("", Integer.valueOf(value.toString()));
				}
			}*/
			else {
				v = ((VarGrade) v).getCopiaTipo();
			}
		}
		
		return v;
	}
	
	
	private void executeStrlenOperation(
			Controlador c,
			Token cmd,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		
		Variavel var;
		
		Object arg = null;
		Object value = null;
		
		System.out.println("executeStrlenOperation:");
		
	    var = getVariavel((Stack<Object>)args.get(0), c);
	   
	   	Object obj = args.get(1);
		if (obj instanceof List<?>)
			value = getValue(c, (List<Object>) obj);
		else
			value = obj.toString();
		
		
		arg  = args.get(0);
		if(var instanceof VarInteger)
	    {
		   if (value instanceof String)
			   setValue(c, (Stack<Object>) arg, ((String)value).length() );
		   else 
			   gerarErro("Era esperado uma valor string no segundo argumento.");  
	    }
		else
		{
			gerarErro("Era esperado uma variavel int como primeiro argumento.");
		}
	}
	
	private void executeStrcmpOperation(
			Controlador c,
			Token cmd,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		
		Variavel var;
		
		Object arg = null;
		Object value = null;
		Object value2 = null;
		
		System.out.println("executeStrcmpOperation:");
		
	    var = getVariavel((Stack<Object>)args.get(0), c);
	   
	   	Object obj = args.get(1);
		if (obj instanceof List<?>)
			value = getValue(c, (List<Object>) obj);
		else
			value = obj.toString();
		
		Object obj2 = args.get(2);
		if (obj2 instanceof List<?>)
			value2 = getValue(c, (List<Object>) obj2);
		else
			value2 = obj2.toString();
		
		arg  = args.get(0);
		if(var instanceof VarInteger)
	    {
		   if (value instanceof String && value2 instanceof String)
			   setValue(c, (Stack<Object>) arg, ((String)value).compareTo((String)value2) );
		   else 
			   gerarErro("Era esperado uma valor string no segundo e terceiro argumento.");  
	    }
		else
		{
			gerarErro("Era esperado uma variavel int como primeiro argumento.");
		}
	}
	
	private void executeSqrtOperation(
			Controlador c,
			Token cmd,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		
		Variavel var;
		
		Object arg = null;
		Object value = null;
		
		System.out.println("executeSqrtOperation:");
		
	    var = getVariavel((Stack<Object>)args.get(0), c);
	   
	   	Object obj = args.get(1);
		if (obj instanceof List<?>)
			value = getValue(c, (List<Object>) obj);
		else
			value = new Double(obj.toString());
		
		
		arg  = args.get(0);
		if(var instanceof VarReal)
	    {
		   if (value instanceof Double)
			   setValue(c, (Stack<Object>) arg, Math.sqrt((Double)value));
		   else if (value instanceof Integer)
			   setValue(c, (Stack<Object>) arg, Math.sqrt( ((Integer)value).floatValue()) );
		   else if (value instanceof Float)
			   setValue(c, (Stack<Object>) arg, Math.sqrt( ((Float)value)) );
		   else 
			   gerarErro("Era esperado uma valor numerico como segundo argumento.");  
	    }
		else
		{
			gerarErro("Era esperado uma variavel float como primeiro argumento.");
		}
	}
	
	private void executeCosOperation(
			Controlador c,
			Token cmd,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		
		Variavel var;
		
		Object arg = null;
		Object value = null;
		
		System.out.println("executeCosOperation:");
		
	    var = getVariavel((Stack<Object>)args.get(0), c);
	   
	   	Object obj = args.get(1);
		if (obj instanceof List<?>)
			value = getValue(c, (List<Object>) obj);
		else
			value = new Double(obj.toString());
		
		
		arg  = args.get(0);
		if(var instanceof VarReal)
	    {
		   if (value instanceof Double)
			   setValue(c, (Stack<Object>) arg, Math.cos((Double)value));
		   else if (value instanceof Integer)
			   setValue(c, (Stack<Object>) arg, Math.cos( ((Integer)value).floatValue()) );
		   else if (value instanceof Float)
			   setValue(c, (Stack<Object>) arg, Math.cos( ((Float)value)) );
		   else 
			   gerarErro("Era esperado uma valor numerico como segundo argumento.");  
	    }
		else
		{
			gerarErro("Era esperado uma variavel float como primeiro argumento.");
		}
	}
	
	private void executeSinOperation(
			Controlador c,
			Token cmd,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		
		Variavel var;
		
		Object arg = null;
		Object value = null;
		
		System.out.println("executeSinOperation");
		
	    var = getVariavel((Stack<Object>)args.get(0), c);
	   
	   	Object obj = args.get(1);
		if (obj instanceof List<?>)
			value = getValue(c, (List<Object>) obj);
		else
			value = new Double(obj.toString());
		
		
		arg  = args.get(0);
		if(var instanceof VarReal)
	    {
		   if (value instanceof Double)
			   setValue(c, (Stack<Object>) arg, Math.sin((Double)value));
		   else if (value instanceof Integer)
			   setValue(c, (Stack<Object>) arg, Math.sin( ((Integer)value).floatValue()) );
		   else if (value instanceof Float)
			   setValue(c, (Stack<Object>) arg, Math.sin( ((Float)value)) );
		   else 
			   gerarErro("Era esperado uma valor numerico como segundo argumento.");  
	    }
		else
		{
			gerarErro("Era esperado uma variavel float como primeiro argumento.");
		}
	}
	
	private void executeScanfOperation(
			Controlador c,
			Token cmd,
			AbstractArquivo arq,
			List<Object> args) throws TiraTeimaLanguageException, Exception {

		int size = args.size();
		Variavel var;
		
		Object arg = null;
		Object value = null;
		String token = null;
		
		System.out.println("Operacao scanf:");
		
		for (int i=0;i<size;i++)
		{
		   arg = args.get(i);
		   if (!(arg instanceof Stack))
		   {
			   gerarErro("Era esperado uma variavel.");
		   }  
		   var = getVariavel((Stack<Object>)arg, c);
		   
		   token = ((VarFile)arq).getNextToken();
		   value = token;
		   System.out.println("  token: "+token);
		   
		   if (var instanceof VarString)
		   {
			   value = token;
		   }
		   else if(var instanceof VarInteger)
		   {
			   value = new Integer(token);
		   }
		   else if(var instanceof VarReal)
		   {
			   value = new Float(token);
		   }
		   else if(var instanceof VarChar)
		   {
			   value = token.charAt(0);
		   }     
		   setValue(c, (Stack<Object>) arg, value);
		}
		
		((VarFile)arq).atualizaConteudo();
	}
	
	private void executeFReadOperation(
			Controlador c,
			Token cmd,
			AbstractArquivo arq,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		
		Variavel dest = getVariavel((Stack<Object>)args.get(0), c);
		
		int vezes = (new Integer(args.get(2).toString())).intValue();
		for (int i = 0; i < vezes; i++) {
			
		   if (dest instanceof VarArray) {
			   Index indice = new Index(i); 
			   ((Stack<Object>) args.get(0)).add(indice);
		   }
		   
		   Object value = ((VarBinFile) arq).fread(dest);
		   salvaValoresAnteriores(c, previous_values_stack_Fread, (Stack<Object>)args.get(0)); //Usado para não dar problema quando der o revert
		   setValue(c, (Stack<Object>) args.get(0), value);
		   
		   
		   if (dest instanceof VarArray) {
			   ((Stack<Object>) args.get(0)).pop();
		   }
		}
	}
	
	private void executeFWriteOperation(
			Controlador c,
			Token cmd,
			AbstractArquivo arq,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		
		Object value = getValue(c, (Stack<Object>) args.get(0));
		((VarBinFile) arq).fwrite((new Integer(args.get(2).toString())).intValue(), value);
	}
	
	private void executePrintfOperation(
			Controlador c,
			Token cmd,
			AbstractArquivo arq,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		
		//System.out.println("Operacao printf:");
		
		Object obj = "";
		
		int i = 0;
		String str = (String) args.get(i);
		i++;
		
		Pattern pattern = Pattern.compile("%(([0123456789]*s)|([0123456789]*d)|(c)|([0123456789]*\\.?[0123456789]*f))");
		Matcher matcher = pattern.matcher(str);
		while (matcher.find()) {
			obj = args.get(i);
			if (obj instanceof List<?>)
				obj = getValue(c, (List<Object>) obj);
			else
				obj = obj.toString();
			
			if (matcher.group().matches("%[0123456789]*\\.[0123456789]*f")) {
				String num = matcher.group().substring(matcher.group().indexOf(".")+1, matcher.group().length()-1);
				Integer n = new Integer(num);
				n = (int) Math.pow(10.0, n);
				DecimalFormat df = new DecimalFormat("0."+n.toString().replaceFirst("1", ""));
				obj = df.format(obj).replaceAll(",", ".");
			}
			if (matcher.group().matches("%[0123456789]+d") || matcher.group().matches("%[0123456789]+s") || matcher.group().matches("%[0123456789]+f")) {
				String num = matcher.group().substring(1, matcher.group().length()-1);
				Integer n = new Integer(num);
				obj = completaEspacos(n, obj.toString());
			}
			if (matcher.group().matches("%[0123456789]+\\.[0123456789]*f")) {
				String num = matcher.group().substring(1, matcher.group().indexOf("."));
				Integer n = new Integer(num);
				obj = completaEspacos(n, obj.toString());
			}
			if (matcher.group().matches("%[0123456789]*f")) {
				if (obj.toString().substring(obj.toString().indexOf(".")+1).length() > 6) {
					Integer n = (int) Math.pow(10.0, 6);
					DecimalFormat df = new DecimalFormat("0."+n.toString().replaceFirst("1", ""));
					obj = df.format(obj).replaceAll(",", ".");
				}
			}
			str = str.replaceFirst(matcher.group(), obj.toString());
            i++;
        }
		
		((VarFile)arq).printStr(str);
		
		((VarFile)arq).atualizaConteudo();
		
		
		/* Implementação do printF operation funcionando com o ultimo parametro, que indica
		 * a quantidade de vezes que a variavel deve ser gravada no arquivo. ex: printFile(arq, v, 1, 5);
		 * 
		 * 
		 * //System.out.println("Operacao printf:");
				
				//ListIterator<Object> i = args.listIterator();
				Object obj, val;
				String buf = "";
				
				Variavel var = getVariavel((Stack<Object>)args.get(0), c);
				
				int vezes = (new Integer(args.get(2).toString())).intValue();
				
				//while (i.hasNext()) {
				for (int i = 0; i < vezes; i++) {
					obj = args.get(0);
					
					if (obj instanceof List<?>)
					{
						//É uma variavel
						if (var instanceof VarArray) {
							((List<Object>) obj).add(new Index(i));
							
							val = getValue(c, ((List<Object>) obj));
							
							((List<Object>) obj).remove(((List<Object>) obj).size()-1);
						}
						else {
							val = getValue(c, (List<Object>) obj);
							val =  val.toString();
						}
					}
					else
					{
						//Não é uma variavel, é o valor direto
						val =  obj.toString();
					}
					buf = buf+val;
				//}
				
				
					((VarFile)arq).printStr(buf);
					
					((VarFile)arq).atualizaConteudo();
				
				}
		 */
		
		
	}
	
	
	/**
	 * Executa operação de leitura do arquivo solicitada pelo usuário. 
	 * @param g
	 * @param cmd
	 * @param arq
	 * @param args
	 * @throws TiraTeimaLanguageException
	 * @throws Exception
	 */
	private void executeReadOperation(
			Controlador c,
			Token cmd,
			AbstractArquivo arq,
			List<Object> args) throws TiraTeimaLanguageException, Exception {
		/** verifica número de parâmetros */
		int size = args.size();
		if ((size < 1) || (size > 2)) {
			gerarErro("Número de parâmetros incorreto para comando 'read'.");
		}
		
		/** pega o tipo da variável a ser lida */
		Object first = args.get(0);
		if (!(first instanceof Stack))
			gerarErro("Era esperada uma variável.");
		ListIterator<Object> i = ((Stack<Object>) first).listIterator();
		Variavel v = c.mostrador.getCopiaVariavel((String) i.next());
		while (i.hasNext()) {
			Object aux = i.next();
			if (aux instanceof String) {
				v = ((VarRecord) v).getCopiaCampo((String) aux);
			} else {
				v = ((VarGrade) v).getCopiaTipo();
			}
		}
		
		Object value = null;
		if (v instanceof VarString) {
			if (size == 2) {
				Object aux = args.get(1);
				if (!(aux instanceof Integer)) {
					gerarErro("Era esperado um inteiro positivo.");
				}
				
				int length = (Integer) aux;
				value = ((VarText) arq).readString(length);
				
				if (cmd.kind == KW_READLN)
					((VarText) arq).readln();
			} else {
				value = ((VarText) arq).readLine();
			}
		} else {
			if (size > 1)
				gerarErro("Número de parâmetros incorreto para comando 'read'.");
			
			if (v instanceof VarReal) {
				value = ((VarText) arq).readReal();
			} else if (v instanceof VarInteger) {
				value = ((VarText) arq).readInt();
			} else if (v instanceof VarChar) {
				value = ((VarText) arq).read();
			}
			
			if (cmd.kind == KW_READLN)
				((VarText) arq).readln();
		}
		
		setValue(c, (Stack<Object>) first, value);
	}
	
	
	/**
	 * Executa operação de escrita no arquivo.
	 * @param g
	 * @param cmd
	 * @param arq
	 * @param args
	 */
	private void executeWriteOperation(
			Controlador c,
			Token cmd,
			AbstractArquivo arq,
			List<Object> args) {
		
		
		
		Object obj = "";
		
		int i = 0;
		String str = (String) args.get(i);
		i++;
		
		Pattern pattern = Pattern.compile("%(([0123456789]*s)|([0123456789]*d)|(c)|([0123456789]*\\.?[0123456789]*f))");
		Matcher matcher = pattern.matcher(str);
		while (matcher.find()) {
			obj = args.get(i);
			if (obj instanceof List<?>)
				obj = getValue(c, (List<Object>) obj);
			if (matcher.group().matches("%[0123456789]*\\.[0123456789]*f")) {
				String num = matcher.group().substring(matcher.group().indexOf(".")+1, matcher.group().length()-1);
				Integer n = new Integer(num);
				n = (int) Math.pow(10.0, n);
				DecimalFormat df = new DecimalFormat("0."+n.toString().replaceFirst("1", ""));
				obj = df.format(obj).replaceAll(",", ".");
			}
			if (matcher.group().matches("%[0123456789]+d") || matcher.group().matches("%[0123456789]+s") || matcher.group().matches("%[0123456789]+f")) {
				String num = matcher.group().substring(1, matcher.group().length()-1);
				Integer n = new Integer(num);
				obj = completaEspacos(n, obj.toString());
			}
			if (matcher.group().matches("%[0123456789]+\\.[0123456789]*f")) {
				String num = matcher.group().substring(1, matcher.group().indexOf("."));
				Integer n = new Integer(num);
				obj = completaEspacos(n, obj.toString());
			}
			if (matcher.group().matches("%[0123456789]*f")) {
				if (obj.toString().substring(obj.toString().indexOf(".")+1).length() > 6) {
					Integer n = (int) Math.pow(10.0, 6);
					DecimalFormat df = new DecimalFormat("0."+n.toString().replaceFirst("1", ""));
					obj = df.format(obj).replaceAll(",", ".");
				}
			}
			str = str.replaceFirst(matcher.group(), obj.toString());
            i++;
        }
			
		//escreve no arquivo
		if (arq != null) {
			((VarText) arq).write(str.toString());
		}
		else { //escreve no console
			c.console.print(str.toString());
		}
		
	}
	
	private Object completaEspacos(Integer n, String string) {
		String newStr = string;
		while (newStr.length() < n) {
			newStr = " " + newStr;
		}
		return newStr;
	}

	/**
	 * Executa a operação de alerta mostrando um alerta no tirateima 
	 * @param g
	 * @param cmd
	 * @param args
	 */
	private void executeAlertOperation(
			Controlador c,
			Token cmd,
			List<Object> args) {
		
		ListIterator<Object> i = args.listIterator();
		Object obj;
		
		while (i.hasNext()) {
			obj = i.next();
			
			if (obj instanceof List<?>)
				obj = getValue(c, (List<Object>) obj);
			
			//marca estado para mostrar um comentario
			c.alerta.print(obj.toString());
		}
	}
	
	/**
	 * Executa operação de som, tocando um som para o usuário.
	 * @param g
	 * @param cmd
	 */
	private void executeSoundOperation(
			Controlador c,
			Token cmd) {
			//marca estado para tocar um som
			c.alerta.tocaSom();
	}
}
